<html lang="en-US">

<head>
    
<title>《漫谈 MQ》要消息队列（MQ）有什么用？ - 花落雨忧</title>

<meta property="og:title" content="《漫谈 MQ》要消息队列（MQ）有什么用？ - 花落雨忧">



    



    
    <meta property="description" content="大家好，我是煎鱼。想是问题，做是答案。
最近我有一个朋友公司踩了不少消息队列（MQ）的坑，让人无奈不已。因此计划写 MQ 系列的技术文章，来科普更多这块的知识。
目前 MQ 也是互联网应用中非常常用的基础组件了，面试特爱问。基本有一定规模的系统都能看见他的踪影。
无论是 RocketMQ、Kafka、RabbitMQ 等，都围绕着根本的设计出发产生不同的高级功能，甚至可能是雷同的设计有 N 个名 &amp;hellip;">
    <meta property="og:description" content="大家好，我是煎鱼。想是问题，做是答案。
最近我有一个朋友公司踩了不少消息队列（MQ）的坑，让人无奈不已。因此计划写 MQ 系列的技术文章，来科普更多这块的知识。
目前 MQ 也是互联网应用中非常常用的基础组件了，面试特爱问。基本有一定规模的系统都能看见他的踪影。
无论是 RocketMQ、Kafka、RabbitMQ 等，都围绕着根本的设计出发产生不同的高级功能，甚至可能是雷同的设计有 N 个名 &amp;hellip;">
    






<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1">

<link rel="shortcut icon" href="https://www.lican.asia/logo/logo.png" type="image/x-icon" />



<link rel="stylesheet" href="/css/style.min.css" />

<link rel="stylesheet" href="/css/reset.min.css" />




<script src="https://www.lican.asia/js/highlight.min.js"></script>

<script>
hljs.configure({ ignoreUnescapedHTML: true })
hljs.highlightAll();
</script>


<script src="https://www.lican.asia/js/jquery.min.js"></script>




<link href="https://www.lican.asia/css/hugo-code.min.css" rel="stylesheet" />



    <style>
        .post-content img {
            max-width: 400px;
        }
    </style>
</head>

<body id="period" class="home blog">
    <a class="skip-content" href="#main">Press "Enter" to skip to content</a>
    <div id="overflow-container" class="overflow-container">
        <header class="site-header" id="site-header" role="banner">
    <div class="max-width">
        <div id="title-container" class="title-container">
            <div id="site-title" class="site-title"><a href="/">花落雨忧</a></div>
            <p class="tagline">思所及 力所行 方为真.</p>
        </div>
        
        <div id="menu-primary-container" class="menu-primary-container">
            <div class="icon-container">
            </div>
            <div id="menu-primary" class="menu-container menu-primary" role="navigation">
                <nav class="menu">
                    <ul id="menu-primary-items" class="menu-primary-items">
                        
                        
                        <li id="menu-item-0"
                            class="menu-item menu-item-type-custom menu-item-object-custom ">
                            <a href="/posts" aria-current="page" tabindex="0">首页</a></li>
                        
                        <li id="menu-item-1"
                            class="menu-item menu-item-type-custom menu-item-object-custom ">
                            <a href="/tech/" aria-current="page" tabindex="1">技术文档</a></li>
                        
                        <li id="menu-item-2"
                            class="menu-item menu-item-type-custom menu-item-object-custom ">
                            <a href="/article/" aria-current="page" tabindex="2">文章</a></li>
                        
                        <li id="menu-item-3"
                            class="menu-item menu-item-type-custom menu-item-object-custom ">
                            <a href="/project/" aria-current="page" tabindex="3">项目</a></li>
                        
                        <li id="menu-item-4"
                            class="menu-item menu-item-type-custom menu-item-object-custom ">
                            <a href="/about/" aria-current="page" tabindex="4">关于</a></li>
                        
                    </ul>
                </nav>
            </div>
        </div>
    </div>
</header>

        <div id="primary-container" class="primary-container">
            <div class="max-width">
                <section id="main" class="main" role="main">
                    <div id="loop-container" class="loop-container">
                        <div
                            class="post type-post status-publish format-standard hentry entry">
                            <article>
                                <div class="post-container">
                                    <div class="post-header">
                                        <h2 class="post-title">
                                            <a href="/posts/posts/why-mq/">《漫谈 MQ》要消息队列（MQ）有什么用？</a>
                                        </h2>
                                        
                                        <div class="post-byline">Published on
                                            <a class="date" href="javascript:;">2021/12/31</a>
                                            
                                            
                                            
                                            
                                            
                                        
                                    </div>
                                    <div class="post-content">
                                        <p>大家好，我是煎鱼。想是问题，做是答案。</p>
<p>最近我有一个朋友公司踩了不少消息队列（MQ）的坑，让人无奈不已。因此计划写 MQ 系列的技术文章，来科普更多这块的知识。</p>
<p>目前 MQ 也是互联网应用中非常常用的基础组件了，面试特爱问。基本有一定规模的系统都能看见他的踪影。</p>
<p>无论是 RocketMQ、Kafka、RabbitMQ 等，都围绕着根本的设计出发产生不同的高级功能，甚至可能是雷同的设计有 N 个名字。</p>
<h2 id="什么是-mq">什么是 MQ</h2>
<p>MQ 一般代指消息队列（Message Queue）。它是一个抽象层，允许多个进程（可能在不同的机器上）通过各种模式（例如：点对点，发布订阅等）进行通信。</p>
<p>也可以根据不同的实现，它可以被配置为保证可靠性、错误报告、安全、发现、性能等。</p>
<h2 id="为什么需要-mq">为什么需要 MQ</h2>
<p>在当下 MQ 的必要场景，比较经典的说辞就是 “异步、削峰、解耦”。是各类秒杀系统的设计核心，甚至会作为不少云厂商的卖点，每家都有自己的生态圈。</p>
<p>核心分为三个要点：</p>
<ul>
<li>解耦。</li>
<li>削峰。</li>
<li>异步。</li>
</ul>
<h3 id="解耦">解耦</h3>
<p>在业务系统设计中，我们常常会与一个平台系统 A，他汇聚了许许多多的系统的对接。例如，系统 A 作为平台拥有大量用户操作，自然就有非常多的用户行为。</p>
<p>虽然他自己可能不大需要，但是其他子系统就不同了，会要系统 A 来调用他们提供的接口，传输各种行为数据。</p>
<p>其链路依赖如下图：</p>
<p><img src="https://image.eddycjy.com/84478d2799861f81519ede0ba4ceb91d.jpg" alt="多重依赖"></p>
<p>这时候作为平台方的系统 A 就烦死了，来一个要对接一个，就得安排一个人排工期和迭代。对方还有可能出现系统不稳定，还得关注他们的稳定性和诉求。</p>
<p>但用了 MQ 后就不一样了，如下图：</p>
<p><img src="https://image.eddycjy.com/b6c79dbe5c848ed32e347de4042cd9b6.jpg" alt="MQ 解耦直接依赖"></p>
<p>系统 A 只需要将消息放到 MQ 中去，不管以后是对接系统 B、C、D、E&hellip;，他都不需要太关心，不用一个个对接。用业务同学的话来讲，就是：“自己看文档，去 MQ 里拿，别来骚扰我”。</p>
<p>以此 MQ 达到了系统间解耦的目的。</p>
<h3 id="削峰">削峰</h3>
<p>在 2C 类别的业务系统中，常常会有活动的概念，要面向用户做促销，像我们常见的双 11、618 都是这类营销，也是营销场景。</p>
<p>但这种场景之下，会对系统产生较大的冲击。类似八二原则，也就是 80% 的流量集中在某个时间冲击进来，形成了流量尖峰（高 QPS），系统会因为承受不了如此大的压力，从而宕机。</p>
<p>如下图：</p>
<p><img src="https://image.eddycjy.com/e396606bb1aec70b43a7016933880f09.jpg" alt="用户直接并发访问"></p>
<p>用户的请求会经由系统 A 直击数据库。当然，在活动场景下的大流量，数据库自然也就撑不住了。</p>
<p>我们可以利用 MQ 做削峰，系统 A 直接把消息写入 MQ，再让系统 B、C、D 自己主动地根据自身情况来 MQ 拉取消息，又或是接受消息的推送：</p>
<p><img src="https://image.eddycjy.com/126ec27324c95ce6311078a8e8849d54.jpg" alt="利用 MQ 削峰"></p>
<p>这样一来，MQ 作为一个 “转发器”，流量不会直接打到底层，也保证了各业务系统可根据自己的实际负载来决定消费消息的速度，起到流量削峰放缓的作用。</p>
<h3 id="异步">异步</h3>
<p>在没有引入 MQ 组件的时候，我们系统 A 因业务需求要调好几个接口时，都可能需要专门的写个异步操作，否则就会导致阻塞等待响应过久。</p>
<p>但是使用 MQ 后，系统只需要快速地将消息写入 MQ 中，接着就可以返回了：</p>
<p><img src="https://image.eddycjy.com/40efbfcc5453aff5b58e85d11fb3d291.jpg" alt="MQ 异步操作"></p>
<p>也就是真正的业务操作，被异步化了。“内部” 的区域是业务系统自身需要关注的，而经由 MQ 的 “外部” 操作与系统 A 无关，自然异步处理也问题不大。</p>
<h2 id="mq-三要素">MQ 三要素</h2>
<p>MQ 一共有三个基本角色，分别是：</p>
<ul>
<li>生产者（Producer）：负责生产消息。</li>
<li>消费者（Consumer）：负责消费消息。</li>
<li>队列（Queue）：负责存储消息。</li>
</ul>
<p>这么一看，MQ 就是一个很基础的东西，基本就是一发一存一消费的模型：</p>
<p><img src="https://image.eddycjy.com/60a3665e5c14ec8b18a0ec14c31b91b4.jpg" alt="MQ 三要素"></p>
<ol>
<li>
<p>在 MQ 中传来传去的内容：就是 “消息”，消息是我们业务要传输的数据内容。内容格式为自定义，只要两边商议清楚能解析出来即可。比较常见是像是：JSON、Protobuf 等。</p>
</li>
<li>
<p>消息在 MQ 的队列组件：承载着传输消息的作用，队列是先进先出的数据结构，生产者的消息入队就是发消息，消费者消费消息，也就是队列出队。</p>
</li>
</ol>
<h2 id="消息模型">消息模型</h2>
<p>随着消息的不断规模使用和应用，目前业内常见的有两种模型：</p>
<ul>
<li>点对点模型。</li>
<li>发布/订阅模型。</li>
</ul>
<h3 id="点对点模型">点对点模型</h3>
<p>点对点是 MQ 最初的结构，也就是 “生产者-队列-消费者” 的模型：</p>
<p><img src="https://image.eddycjy.com/597c3a216c23124f0a0c855b5777a85d.jpg" alt="点对点模型"></p>
<p>生产者将消息写入队列，消费者再从队列中读取出消息出来，完成一个标准动作。</p>
<p>当然，在真实环境中，是允许有多个生产者和多个消费者的，也可以根据不同的业务诉求做队列的隔离。</p>
<h3 id="发布订阅模型">发布/订阅模型</h3>
<p>发布/订阅是 MQ 逐渐延伸出来的诉求，因为在实际业务场景中，我们需要将一份消息分发给多个消费者。</p>
<p>多个消费者都要针对这份数据做一些自己的业务处理，那么点对点的就不合适了，除非点对点的开通 N 个队列，但消息的体量可也不少，也不高效，这显然很浪费。</p>
<p>从业务场景来讲，就像平时系统 A 有一份用户行为数据，下游有 N 个系统需要，那咋办。最适合的就是 “发布者-Topic-订阅者” 的模型：</p>
<p><img src="https://image.eddycjy.com/a64d93b952cb9953af355cf2e56ee1a4.jpg" alt="发布/订阅模型"></p>
<p>在该模型中，“生产者” 变成 “发布者”，“消费者” 变成了 “订阅者”，以往的 “队列” 也改变了他单一的属性，拆成了更多的组件。一般就是 “主题” 了，也就是 Topic 来做消息存储等。</p>
<p>订阅者只需要订阅 Topic，就可以收到发布者每次发布的这个 Topic 的全量消息，以此达到诉求。</p>
<h2 id="总结">总结</h2>
<p>在今天这篇文章中，我们介绍了消息队列（MQ）的相关核心内容：</p>
<ul>
<li>MQ 基本介绍和说明。</li>
<li>MQ 常见的三要素和三大特性进行了分析说明</li>
<li>MQ 常见的 “点对点” 和 “发布/订阅” 模型。</li>
</ul>
<p>MQ 总是有利有弊的，在初步了解后，接下来的文章我们将会持续剖析，欢迎关注煎鱼，继续学习 ：）</p>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://stackoverflow.com/questions/2868800/what-is-an-mq-and-why-do-i-want-to-use-it">What is an MQ and why do I want to use it?</a></li>
<li><a href="https://www.zhihu.com/question/54152397">消息队列（mq）是什么？</a></li>
<li><a href="https://blog.csdn.net/maihilton/article/details/81628152">MQ 消息队列的解耦、接口异步处理、削峰</a></li>
</ul>


                                        
                                        
                                        
                                        <div class="rp4wp-related-posts">
                                            <h3>相关文章</h3>
                                            <ul>
                                                
                                                <li>
                                                    <div class="rp4wp-related-post-content">
                                                        <a
                                                            href="https://www.lican.asia/posts/posts/mq-nodus/">《漫谈 MQ》设计 MQ 的 3 个难点</a>
                                                    </div>
                                                </li>
                                                
                                            </ul>
                                        </div>
                                        
                                        
                                    </div>

                                    
                                    
                                    

                                    
                                    <div class="post-meta">
                                        
                                        
                                        <div class="post-tags">
                                            <ul>
                                            
                                            <li>
                                                <a href="/tags/mq" title="View all posts tagged match">mq</a>
                                            </li>
                                            
                                            </ul>
                                        </div>
                                        
                                        
                                        <nav class="further-reading">
                                            
                                            <div class="previous">
                                                <span>&lt;&lt; Prev</span>
                                                <a href="https://www.lican.asia/posts/posts/mq-nodus/"
                                                    rel="prev">《漫谈 MQ》设计 MQ 的 3 个难点</a> </div>
                                            
                                            
                                            <div class="next">
                                                <span>Next >></span>
                                                <a href="https://www.lican.asia/posts/posts/go/empty-struct/">详解 Go 空结构体的 3 种使用场景</a> 
                                            </div>
                                            
                                        </nav>
                                    </div>
                                    
                                    

                                    
                                    
                                    

                                </div>
                            </article>
                        </div>
                    </div>
                </section>
                <aside class="sidebar sidebar-primary" id="sidebar-primary" role="complementary">
    <h1 class="screen-reader-text">Sidebar</h1>
    

    
    
    <section id="text-2" class="widget widget_text">
        <div class="textwidget">
            
            <div id="profile">
                <div id="profile_picture"><img src="https://www.lican.asia/logo/logo.png"></div>
                <div id="profile_intro">
                    <p><span class="name">Lican</span></p>
                    <p class="intro">全栈开发者，爱好造轮子。</p>
                </div>
            </div>
            
            <p>
                <script type="text/javascript">
                    (function ($) {
                        $(document).ready(function () {
                            var menuPrimaryContainer = $('#menu-primary-container');
                            var profile = $('#text-2');
                            $('#toggle-navigation').click(function () {
                                if (menuPrimaryContainer.hasClass('open')) {
                                    profile.removeClass('open');
                                } else {
                                    profile.addClass('open');
                                }
                            });
                        });
                    })(jQuery);
                </script>
            </p>
        </div>
    </section>
    
    
    
    
    
    <section id="text-5" class="widget widget_text">
        <h2 class="widget-title">开源项目</h2>
        <div class="textwidget">
            <div id="projects" style="line-height: 22px;">
                
                <a href="https://github.com/idoubi/gonews"
                    target="_blank">gonews</a>: &nbsp;Daily news for golang<br>
                
                <a href="https://github.com/idoubi/sql2struct"
                    target="_blank">sql2struct</a>: &nbsp;Generate go struct according to SQL<br>
                
                <a href="https://github.com/idoubi/goz"
                    target="_blank">goz</a>: &nbsp;Request library used in golang<br>
                
        </div>
    </section>
    
    

    
    
    
    
    <section id="qrcode" class="widget widget_media_image">
        <h2 class="widget-title">微信公众号</h2>
        <img width="258" height="258"
            src="https://www.lican.asia/wechat/lican.png"
            class="image wp-image-5514  attachment-full size-full" alt=""
            style="max-width: 100%; height: auto;"
            sizes="(max-width: 258px) 100vw, 258px">
    </section>
    
    

    
    
    

    
    
    

    
    
    
    
</aside>
            </div>
        </div>

        <footer id="site-footer" class="site-footer" role="contentinfo">
    <div class="max-width">
    </div>
    <div class="footer">
        <div id="footercontent">
            © lican.asia All rights reserved<br/>
            Built with Hugo Theme <a href="https://github.com/idoubi/hugo-theme-period" target="_blank">Period</a>
        </div>
    </div>
</footer>

<script>
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?e8351b6d4626d5881d439ea1f6184baa";
      var s = document.getElementsByTagName("script")[0]; 
      s.parentNode.insertBefore(hm, s);
    })();
</script>
    
    
    </div>
    
</body>

</html>